# java

# 事务区别

@Transactional(rollbackFor =Exception.class)
所有异常都会回滚,
@Transactional
只有运行时异常会回滚
throw new BusinessException("退款失败");

# 同一个实现类事务失效

# 方法1 自调用走代理(最快)

import org.springframework.aop.framework.AopContext;

@Slf4j
@Service
@EnableAspectJAutoProxy(exposeProxy = true)
public class PointSmallOrderRefundServiceImpl implements PointSmallOrderRefundService {

    public void methodA() {
        ((PointSmallOrderRefundService) AopContext.currentProxy()).methodB();
    }
    
    @Transactional
    public void methodB() {
        // 事务逻辑
    }
}

# 方法2 拆到另一个 Service(最推荐)

@Service
public class OrderService {

    @Autowired
    private OrderTxService orderTxService;

    public void methodA() {
        orderTxService.methodB();
    }
}

@Service
public class OrderTxService {

    @Transactional
    public void methodB() {
        // 事务逻辑
    }
}

# 方法3 ApplicationContext 取自己

@Autowired
private ApplicationContext applicationContext;

public void methodA() {
    applicationContext.getBean(YourService.class).methodB();
}

# mq死锁问题

在 @RabbitListener 中,Spring AMQP 会自动管理 Channel 生命周期,消息处理完成后框架会自动归还 Channel 到缓存。手动调用 channel.close() 会:

触发 CachedChannelInvocationHandler.logicalClose() → returnToCache() → setAfterAckCallback() 此过程需要获取 PublisherCallbackChannelImpl(锁B),但当前线程已持有 LinkedList(锁A) 与此同时,AMQP Connection 线程持有锁B,需要锁A,形成 ABBA 死锁

# 线程日志

"org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-1":
	at org.springframework.amqp.rabbit.connection.PublisherCallbackChannelImpl.setAfterAckCallback(PublisherCallbackChannelImpl.java:135)
	- waiting to lock <0x00000000895827e8> (a org.springframework.amqp.rabbit.connection.PublisherCallbackChannelImpl)
	at sun.reflect.GeneratedMethodAccessor1057.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.amqp.rabbit.connection.CachingConnectionFactory$CachedChannelInvocationHandler.invoke(CachingConnectionFactory.java:1110)
	- locked <0x0000000089582d10> (a java.lang.Object)
	at com.sun.proxy.$Proxy638.setAfterAckCallback(Unknown Source)
	at org.springframework.amqp.rabbit.connection.CachingConnectionFactory$CachedChannelInvocationHandler.returnToCache(CachingConnectionFactory.java:1198)
	at org.springframework.amqp.rabbit.connection.CachingConnectionFactory$CachedChannelInvocationHandler.logicalClose(CachingConnectionFactory.java:1189)
	at org.springframework.amqp.rabbit.connection.CachingConnectionFactory$CachedChannelInvocationHandler.invoke(CachingConnectionFactory.java:1063)
	- locked <0x000000008285dae0> (a java.util.LinkedList)

# 方案1 代码优化(移除channel.close())

@RabbitListener
public void consume(
    Message message,
    Channel channel,
    @Header(AmqpHeaders.DELIVERY_TAG) long tag){

    try{
        //业务处理
        channel.basicAck(tag,false);
        //channel.close();
    }catch(Exception e){
        channel.basicNack(tag,false,true);
    }

}

# 方案2 升级mq版本

Spring Boot 2.7.x + Spring AMQP 2.4.x + RabbitMQ 3.12/3.13

# java项目改成web项目

在项目上点右键,进入属性(properties),在左侧列表项目中点击选择“Project Facets”,在右侧选择“Dynamic Web Module”和"Java",点击OK保存即可。

image-20250822175813587

# idea清除缓存

image-20251211134031350

image-20251211134051224

# Tomcat无法启动

Server Tomcat v7.0 Server at localhost failed to start.

出现这个问题是因为web.xml里的配置不对

Tomcat在eclipse里面能正常启动,而在浏览器中访问http://localhost:8080/不能访问,且报404错

参考链接:

http://blog.csdn.net/qq_32131499/article/details/50803479

http://www.educity.cn/wenda/466412.html

通过右键单击tomcat服务器选择 Add and Remove,在弹出的对话框中移除已部署的项目

image-20250822175947351

通过右键单击tomcat服务器选择 Clean之后就可以编辑

image-20250822175956238

双击tomcat服务器,将Use workspace metadata修改为Use Tomcat installation,

修改"Deploy Path",将值默认是"wtpwebapps",把它改成"webapps"

image-20250822180029622

重启tomcat服务器,访问http://localhost:8080 (opens new window)则能正常访问了

//fastjson
//1将对象转换成为字符串
String str = JSON.toJSONString(infoDo);

//2将字符串转换成为对象
InfoDo infoDo = JSON.parseObject(strInfoDo, InfoDo.class);

JSONObject jsonObject = JSONObject.parseObject(str);

Map<String, Object> map2 = (Map) JSON.parse(json);

//3将对象集合转换成为字符串
String users = JSON.toJSONString(users);

//4将字符串转换成为对象集合
List<User> userList = JSON.parseArray(userStr, User.class);



JSONUtils.toJSONString(map);


//CacheAPI

//BigDecimal 比较大小

BigDecimal a = new BigDecimal (101);
BigDecimal b = new BigDecimal (111);
 
//使用compareTo方法比较
//注意:a、b均不能为null,否则会报空指针
if(a.compareTo(b) == -1){
    System.out.println("a小于b");
}
 
if(a.compareTo(b) == 0){
    System.out.println("a等于b");
}
 
if(a.compareTo(b) == 1){
    System.out.println("a大于b");
}
 
if(a.compareTo(b) > -1){
    System.out.println("a大于等于b");
}
 
if(a.compareTo(b) < 1){
    System.out.println("a小于等于b");
}

String 转date
DateUtils.parseDate("2018-01-31","yyyy-MM-dd HH:mm:ss")
date 转 string
String date = DateFormatUtils.format(new Date(), "yyyy-MM-dd");


# map前匹配
https://issues.apache.org/jira/browse/COLLECTIONS-586
        Trie<String,String> lm = new PatriciaTrie<String>();
        lm.put("a.a1","11");
        lm.put("a.a12","12");
        lm.put("b.b1","13");
        lm.put("c.c1","14");
        lm.put("c.c1","15");
        SortedMap<String, String> prefixMap = lm.prefixMap("a.");
        System.out.println(prefixMap.toString());


		// LocalDate类 获取当前日期

		LocalDate date = LocalDate.now();
		System.out.print(date.getYear() + "年");
		System.out.print(date.getMonthValue() + "月");
		System.out.println(date.getDayOfMonth() + "日");
		System.out.println(date.toString());

		// LocalTime类 获取当前时间
		LocalTime time = LocalTime.now();
		System.out.print(time.getHour() + "时");
		System.out.print(time.getMinute() + "分");
		System.out.println(time.getSecond() + "秒");
		System.out.println(time.toString());

		// LocalDateTime类 获取年月日时分秒
		LocalDateTime date2 = LocalDateTime.now();
		System.out.print(date2.getYear() + "年");
		System.out.print(date2.getMonthValue() + "月");
		System.out.print(date2.getDayOfMonth() + "日");
		System.out.print(date2.getHour() + "时");
		System.out.print(date2.getMinute() + "分");
		System.out.println(date2.getSecond() + "秒");
		System.out.println(date2.toString());
		
		//DateTimeFormatter类 解析日期格式
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd:HH:mm:ss");
		LocalDateTime date3 = LocalDateTime.parse("2017-05-15:12:30:50",formatter);
		System.out.println(date3);
		
		//ZonedDateTime类   将日期转成字符串
		ZonedDateTime date4 = ZonedDateTime.now();
		DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd:HH:mm:ss");
		String strDate = date4.format(format);
		System.out.println(strDate);


idea插件
    RestfulToolkit 

Jsoup发送https请求的问题 https://www.cnblogs.com/ylz8401/p/6795933.html https://www.cnblogs.com/Retired-lad/p/16229178.html