init
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
package nl.org.transactionaldemo;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class StartApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(StartApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package nl.org.transactionaldemo.server.JDK新特性.stream流;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/*
|
||||
* @author ZZQ
|
||||
* @Date 2023/4/27 13:46
|
||||
*/
|
||||
public class StreamDemo {
|
||||
public static void main(String[] args) {
|
||||
List<DataEntity> list = extracted(100);
|
||||
//1.字段汇总
|
||||
Set<String> collect = list.stream()
|
||||
.map(DataEntity::getName).collect(Collectors.toSet());
|
||||
//2.条件过滤
|
||||
List<DataEntity> collect1 = list.stream().filter(dataEntity -> dataEntity.getClassNo().equals("NO.3")).collect(Collectors.toList());
|
||||
//3.分组
|
||||
Map<String, List<DataEntity>> map = list.stream().collect(Collectors.groupingBy(dataEntity -> dataEntity.getClassNo()));
|
||||
//4.转换
|
||||
Map<String, DataEntity> map2 = list.stream().collect(HashMap::new, (k, v) -> k.put(v.getName(), v), HashMap::putAll);
|
||||
|
||||
}
|
||||
|
||||
private static List extracted(int count) {
|
||||
List<DataEntity> list = new ArrayList<>();
|
||||
for (int i = 0; i < count; i++) {
|
||||
DataEntity entity = new DataEntity();
|
||||
entity.setName(UUID.randomUUID().toString());
|
||||
entity.setAge(new Random().nextInt(20)+1);
|
||||
entity.setClassNo("NO."+(i%3+1));
|
||||
list.add(entity);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
class DataEntity{
|
||||
private String name;
|
||||
private Integer age;
|
||||
private String classNo;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(Integer age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public String getClassNo() {
|
||||
return classNo;
|
||||
}
|
||||
|
||||
public void setClassNo(String classNo) {
|
||||
this.classNo = classNo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DataEntity{" +
|
||||
"name='" + name + '\'' +
|
||||
", age=" + age +
|
||||
", classNo='" + classNo + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package nl.org.transactionaldemo.server.JDK新特性.函数式接口;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
/*
|
||||
* @author ZZQ
|
||||
* @Date 2023/4/27 14:28
|
||||
*/
|
||||
public class FuntureDemo {
|
||||
public static void main(String[] args) {
|
||||
//1.接口继承:重写方法
|
||||
NumProcess numProcess = new NumProcess();
|
||||
numProcess.process(3);
|
||||
|
||||
//2.正常业务处理:文字处理业务中需要引入数字处理业务
|
||||
StringProcess process = new StringProcess();
|
||||
process.process();
|
||||
|
||||
//3.以参数的形式带入
|
||||
process.process(new NumProcess());
|
||||
|
||||
//4.匿名内部类
|
||||
process.process(new Process() {
|
||||
@Override
|
||||
public Object process(Object o) {
|
||||
return (Integer)o*2;
|
||||
}
|
||||
});
|
||||
//5.函数式接口
|
||||
process.process((a)-> ((Integer) a)*2);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface Process<T,R>{
|
||||
R process(T t);
|
||||
}
|
||||
class NumProcess implements Process<Integer,Integer>{
|
||||
@Override
|
||||
public Integer process(Integer integer) {
|
||||
return integer*2;
|
||||
}
|
||||
}
|
||||
class StringProcess implements Process<Process,String>{
|
||||
@Override
|
||||
public String process(Process process) {
|
||||
return "NO."+process.process(3);
|
||||
}
|
||||
public String process() {
|
||||
//使用到数据处理业务:
|
||||
NumProcess numProcess = new NumProcess();
|
||||
return "NO."+numProcess.process(3);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package nl.org.transactionaldemo.server.事务.事务注解;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class GenCodeServiceImpl {
|
||||
|
||||
|
||||
// @Override
|
||||
// @Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||
// public String codeDemo(Map form) {
|
||||
// String code = (String) form.get("code");
|
||||
// String id = this.queryIdByCode(code);
|
||||
// //如果flag=1就执行更新数据库的操作
|
||||
// String flag = (String) form.get("flag");
|
||||
// WQLObject wo = WQLObject.getWQLObject("sys_code_rule_detail");
|
||||
// JSONArray ja = wo.query("code_rule_id = '" + id + "' order by sort_num FOR UPDATE").getResultJSONArray(0);
|
||||
// String demo = "";
|
||||
// boolean is_same = true;
|
||||
// for (int i = 0; i < ja.size(); i++) {
|
||||
// String value = "";
|
||||
// JSONObject jo = ja.getJSONObject(i);
|
||||
// //固定直接取值
|
||||
// if (jo.getString("type").equals("01")) {
|
||||
// value = jo.getString("init_value");
|
||||
// }
|
||||
// //日期判断数据库的值与当前值是否相同来决定顺序的值
|
||||
// if (jo.getString("type").equals("02")) {
|
||||
// String current_value = jo.getString("current_value");
|
||||
// Date date = DateUtil.date();
|
||||
// String format = jo.getString("format");
|
||||
// String now_date = DateUtil.format(date, format);
|
||||
// if (!now_date.equals(current_value)) {
|
||||
// is_same = false;
|
||||
// }
|
||||
// if (flag.equals("1")) {
|
||||
// jo.put("init_value", now_date);
|
||||
// jo.put("current_value", now_date);
|
||||
// }
|
||||
// value = now_date;
|
||||
// }
|
||||
// //顺序的值:如果日期一样就+步长,等于最大值就归为初始值;日期不一样就归为初始值
|
||||
// if (jo.getString("type").equals("03")) {
|
||||
// String num_value = "";
|
||||
// int step = jo.getInteger("step");
|
||||
// Long max_value = jo.getLong("max_value");
|
||||
// if (!is_same || (jo.getLongValue("current_value") + step > max_value)) {
|
||||
// num_value = jo.getString("init_value");
|
||||
// } else {
|
||||
// num_value = (jo.getInteger("current_value") + step) + "";
|
||||
// }
|
||||
// int size = num_value.length();
|
||||
// int length = jo.getInteger("length");
|
||||
// String fillchar = jo.getString("fillchar");
|
||||
// for (int m = 0; m < (length - size); m++) {
|
||||
// value += fillchar;
|
||||
// }
|
||||
// value += num_value;
|
||||
// if (flag.equals("1")) {
|
||||
// if (!is_same) {
|
||||
// int init_value = jo.getInteger("init_value");
|
||||
// if (StrUtil.isEmpty((init_value + ""))) {
|
||||
// throw new BadRequestException("请完善编码数值的初始值!");
|
||||
// }
|
||||
// jo.put("current_value", init_value + "");
|
||||
// } else {
|
||||
// int num_curr = jo.getInteger("current_value");
|
||||
// if (num_curr >= max_value) {
|
||||
// num_curr = jo.getInteger("init_value");
|
||||
// jo.put("current_value", num_curr + "");
|
||||
// }else{
|
||||
// jo.put("current_value", (num_curr + step) + "");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// demo += value;
|
||||
// if (flag.equals("1")) {
|
||||
// wo.update(jo);
|
||||
// }
|
||||
// }
|
||||
// return demo;
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package nl.org.transactionaldemo.server.事务.编程事务;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.DefaultTransactionDefinition;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import java.util.*;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/*
|
||||
* 分段回回滚:
|
||||
* 注意事项:
|
||||
* 1.思考资源释放问题,spring是怎么释放资源
|
||||
* 2.为什么外层需要加@Transactional 手写编程事务不会报错,原理是什么
|
||||
* 3.封装手写编程事务,只让用户关注自身业务代码。可以参考.jdk8特性:Function等函数表达式的使用
|
||||
* 4.jdk8特性:stream流管道处理替换for循环的学习
|
||||
*/
|
||||
public class TransationDemo {
|
||||
|
||||
//分批回滚:每个for循环都会占用链接
|
||||
@Autowired
|
||||
private PlatformTransactionManager txManager;
|
||||
|
||||
// @Transactional
|
||||
public void creteTask(JSONArray request){
|
||||
|
||||
List<TransactionStatus> statusCollent = new ArrayList<>();
|
||||
try {
|
||||
HashMap<String, TransactionStatus> map = new HashMap<>();
|
||||
for (int i = 0; i < request.size(); i++) {
|
||||
//生成新事务
|
||||
JSONObject param = request.getJSONObject(i);
|
||||
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
|
||||
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
TransactionStatus status = txManager.getTransaction(def);
|
||||
String taskId = IdUtil.randomUUID();
|
||||
//业务代码,生成任务
|
||||
//bussTab.insert(param)
|
||||
//taskTab.insert(taskId);
|
||||
map.put(taskId,status);
|
||||
statusCollent.add(status);
|
||||
}
|
||||
//acs反馈异常taskid
|
||||
List<String> errorTaskIds = new ArrayList<>();
|
||||
errorTaskIds.add("1232");
|
||||
errorTaskIds.add("3224");
|
||||
List<TransactionStatus> errCollect = map.entrySet().stream()
|
||||
.filter(tmap -> errorTaskIds.contains(tmap.getKey()))
|
||||
.map(tmap -> tmap.getValue())
|
||||
.collect(Collectors.toList());
|
||||
//异常的资源回滚
|
||||
for (TransactionStatus status : errCollect) {
|
||||
statusCollent.remove(status);
|
||||
txManager.rollback(status);
|
||||
}
|
||||
}finally {
|
||||
//剩余资源资全部提交
|
||||
if (!CollectionUtils.isEmpty(statusCollent)){
|
||||
for (TransactionStatus value : statusCollent) {
|
||||
txManager.commit(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//封装参考
|
||||
class TransactionManagerUtil{
|
||||
|
||||
public static void main(String[] args) {
|
||||
//demo:
|
||||
JSONArray request = new JSONArray();
|
||||
TransactionManagerUtil.openTransaction((req, allTransactionConsumer) -> {
|
||||
for (Object param : req) {
|
||||
String taskId = UUID.randomUUID().toString();
|
||||
allTransactionConsumer.accept(taskId);
|
||||
//业务代码,生成任务
|
||||
//bussTab.insert(param)
|
||||
//taskTab.insert(taskId);
|
||||
}
|
||||
//acs反馈异常taskid
|
||||
ArrayList errorTask = new ArrayList();
|
||||
return errorTask;
|
||||
},request);
|
||||
}
|
||||
|
||||
|
||||
static Object openTransaction(BiFunction<JSONArray, Consumer<String>,List> function, JSONArray request){
|
||||
PlatformTransactionManager txManager = null; //SpringContextHolder.getBean(PlatformTransactionManager.class);
|
||||
Map<String, TransactionStatus> statusMap = new HashMap<>();
|
||||
List<TransactionStatus> errTask;
|
||||
try {
|
||||
//创建所有事务集合
|
||||
Consumer<String> allTransactionConsumer = task -> {
|
||||
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
|
||||
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
TransactionStatus status = txManager.getTransaction(def);
|
||||
statusMap.put(task,status);
|
||||
};
|
||||
//业务
|
||||
errTask = function.apply(request,allTransactionConsumer);
|
||||
//过滤异常事务的任务id
|
||||
List<TransactionStatus> collect = statusMap.entrySet().stream()
|
||||
.filter(tmap -> errTask.contains(tmap.getKey()))
|
||||
.map(tmap -> tmap.getValue())
|
||||
.collect(Collectors.toList());
|
||||
for (TransactionStatus status : collect) {
|
||||
statusMap.remove(status);
|
||||
txManager.rollback(status);
|
||||
}
|
||||
}finally {
|
||||
//释放剩余资源
|
||||
if (!CollectionUtils.isEmpty(statusMap)){
|
||||
for (TransactionStatus value : statusMap.values()) {
|
||||
txManager.commit(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//封装参考
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package nl.org.transactionaldemo.server.锁;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/*
|
||||
* @author ZZQ
|
||||
* @Date 2023/4/19 12:55
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/sync")
|
||||
public class SyncController {
|
||||
|
||||
@RequestMapping("/block")
|
||||
public String syncBlock(@RequestBody JSONObject param) throws InterruptedException {
|
||||
/**
|
||||
* 数据处理过程:
|
||||
* 通过类型解析器解析输入流:根据targetType生成参数对象:newInstance;
|
||||
* String str = currLen == 0 ? "" : new String(this._currentSegment, 0, currLen);
|
||||
*/
|
||||
synchronized (param.getString("type")){
|
||||
System.out.println(System.identityHashCode(param.getString("type")));
|
||||
System.out.println(System.identityHashCode(param.getString("type").intern()));
|
||||
Thread.sleep(5000);
|
||||
System.out.println("----------"+Thread.currentThread().getName()+"----------");
|
||||
return param.getString("type")+" sucess!!!";
|
||||
}
|
||||
}
|
||||
}
|
||||
47
transactional-demo/src/main/resources/application.yml
Normal file
47
transactional-demo/src/main/resources/application.yml
Normal file
@@ -0,0 +1,47 @@
|
||||
|
||||
spring:
|
||||
datasource:
|
||||
druid:
|
||||
db-type: com.alibaba.druid.pool.DruidDataSource
|
||||
driverClassName: com.mysql.cj.jdbc.Driver
|
||||
#url: jdbc:log4jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:hl_one_mes}?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&useOldAliasMetadataBehavior=true&allowPublicKeyRetrieval=true&useSSL=false
|
||||
url: jdbc:mysql://${DB_HOST:192.168.81.252}:${DB_PORT:3306}/${DB_NAME:hl_one_mes}?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&useOldAliasMetadataBehavior=true&allowPublicKeyRetrieval=true&useSSL=false
|
||||
username: ${DB_USER:root}
|
||||
#password: ${DB_PWD:P@ssw0rd}
|
||||
#password: ${DB_PWD:root}
|
||||
password: ${DB_PWD:Root.123456}
|
||||
# 初始连接数
|
||||
initial-size: 5
|
||||
# 最小连接数
|
||||
min-idle: 15
|
||||
# 最大连接数
|
||||
max-active: 30
|
||||
# 是否自动回收超时连接
|
||||
remove-abandoned: true
|
||||
# 超时时间(以秒数为单位)
|
||||
remove-abandoned-timeout: 180
|
||||
# 获取连接超时时间
|
||||
max-wait: 3000
|
||||
# 连接有效性检测时间
|
||||
time-between-eviction-runs-millis: 60000
|
||||
# 连接在池中最小生存的时间
|
||||
min-evictable-idle-time-millis: 300000
|
||||
# 连接在池中最大生存的时间
|
||||
max-evictable-idle-time-millis: 900000
|
||||
# 指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除
|
||||
test-while-idle: true
|
||||
# 指明是否在从池中取出连接前进行检验,如果检验失败, 则从池中去除连接并尝试取出另一个
|
||||
test-on-borrow: true
|
||||
# 是否在归还到池中前进行检验
|
||||
test-on-return: false
|
||||
# 检测连接是否有效
|
||||
validation-query: select 1
|
||||
# 配置监控统计
|
||||
webStatFilter:
|
||||
enabled: true
|
||||
stat-view-servlet:
|
||||
enabled: true
|
||||
url-pattern: /druid/*
|
||||
reset-enable: false
|
||||
filters:
|
||||
DruidFilter,stat
|
||||
@@ -0,0 +1,13 @@
|
||||
package nl.org.transactionaldemo;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
class TransactionalDemoApplicationTests {
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user