Spring、MySQL、日期、BigDecimal、集合、反射、序列化中的坑与使用指南
创始人
2024-01-13 04:10:54

文章目录

  • MySQL中的坑
    • MySQL断开连接
    • Mysql表字段设置为not null
    • 如何解决网络瓶颈
    • 核心流程的性能查看
  • Spring中的坑与使用
    • 注意springboot的配置文件先后顺序
    • 定时任务不进行
    • lombok的不适用场景
    • Spring的Bean默认名称生成规则
    • new出来的对象不被Spring所管理
    • SpringBean相关的注解
    • Spring出现循环依赖
    • Bean的生命周期使用
    • SpringBoot测试
      • pom文件
      • 代码
    • @Transactional的使用
  • 集合、接口中的坑
    • 对象一定要初始化!
    • 避免空指针
    • for循环
    • 要好好判等!
    • 抽象类与接口
  • BigDecimal等大数
    • 浮点数的计算,使用字符串初始化!!
    • 比较浮点数相等compareTo不用equals
    • 数值溢出问题
    • 精度问题
    • 除法除不尽抛异常
    • long类型数字加上L,float加上F
  • 日期
    • 日期计算LocalDateTime
    • SimpleDateFormat的使用 以及线程不安全
    • 时间格式转换
  • 反射、序列化
    • 反射
    • Serializable
    • 深拷贝

MySQL中的坑

MySQL断开连接

默认8小时–>没请求,断开连接

修改配置,避免断开连接
sql方式

interactive_timeout  wait_timeout
set global 

配置文件方式
80小时没请求就断开

[mysqld]
interactive_timeout =288000
wait_timeout=288000

Mysql表字段设置为not null

如何解决网络瓶颈

  1. 扩容
  2. 分散
  3. 压缩

核心流程的性能查看

在代码里加入一个日志打印,悄悄的把每个步骤的耗时打印出来,自己看一看,然后看看核心流程的时间耗时多长,有没有优化的空间

Spring中的坑与使用

注意springboot的配置文件先后顺序

定时任务不进行

线程数默认为1

在这里插入图片描述

java代码方式

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;@Configuration
public class ScheduleConfig {@Beanpublic TaskScheduler getTaskScheduler() {ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();taskScheduler.setPoolSize(5);//taskScheduler.getActiveCount();return taskScheduler;}
}

lombok的不适用场景

  1. 单字母驼峰
  2. 有子类继承
  3. 尽量手动生成!!

Spring的Bean默认名称生成规则

Spring默认包扫描机制:SpringApplication—>所在包及其子包下的所有目录
@ComponentScan

@ComponentScan(value = {"com.example"})

默认:首字母小写,其他不变
开头第一个字母大写,第二个字母也大写,则不变,即名称为原类名

new出来的对象不被Spring所管理

需要成为Spring容器中的实例,才可以@Autowired

SpringBean相关的注解

@Autowired:默认按类型注入
@Resource:默认byName
@Primary:存在多个相同的Bean,则@Primary用于定义首选项

Spring出现循环依赖

  • 单例模式下
  1. 构造器循环依赖没办法解决
  2. 属性注入
@Autowired
private UserService userService;
  1. set 方式
  • 原型模式下无法解决
    每次都是new出来的,无法缓存对象

Bean的生命周期使用

  1. 实现InitializingBean

该Bean完成实例化后,对该Bean的操作

  1. 实现BeanPostProcessor

对所有的Bean的postProcessBeforeInitializationpostProcessAfterInitialization进行操作

  1. 实现BeanFactoryPostProcessor

spring容器创建后,beanFactory代指spring容器


import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;@Component
public class TestBean implements InitializingBean {@Override// 当前Bean初始化后,还没有注入属性,只会调用一次  3public void afterPropertiesSet() throws Exception {System.out.println("TestBean------>afterPropertiesSet");}
}@Component
class PostProcessor implements BeanPostProcessor {@Override//在Bean初始化前   2public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (!(bean instanceof TestBean)) return bean;System.out.println("TestBean------>postProcessBeforeInitialization");return bean;}@Override//完成Bean的初始化,并且已经注入属性  4public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (!(bean instanceof TestBean)) return bean;System.out.println("TestBean------>postProcessAfterInitialization");return bean;}}@Component
class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Override//在BeanPostProcessor之前执行 1public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)throws BeansException {BeanDefinition testBean = beanFactory.getBeanDefinition("testBean");// 设置怎样定义beantestBean.setScope(BeanDefinition.SCOPE_SINGLETON);System.out.println("TestBean------>TestBeanFactoryPostProcessor");}
}

在这里插入图片描述

SpringBoot测试

pom文件

org.springframework.bootspring-boot-starter-test2.7.3

junitjunit4.13test

代码

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;@SpringBootTest
@RunWith(SpringRunner.class)
class DemoApplicationTests {@Testpublic static void test(String name) {System.out.println(name);}}

@Transactional的使用

org.springframework.bootspring-boot-starter-web

org.springframeworkspring-tx5.3.22

import org.springframework.transaction.annotation.Transactional;
@Transactional
  1. @Transactional所在的方法必须为public
  2. 所在的类必须被spring容器管理!!@Component
  3. 数据库必须支持事务,如InnoDB 支持事务,MyISAM不支持!
  4. 默认情况下, @Transactional 注解 只对抛出的 RuntimeException 异常有效
  5. 指定异常时的事务回滚,使用如下配置
// Exception.class 是所有异常的父类
@Transactional(rollbackFor={RuntimeException.class, Exception.class})
  1. @Transactional 必须加在指定类或方法上,而不是接口上
  2. 没有事务的方法调用本类中另一个@Transactional的方法

此时事务不生效

import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component
public class TestBean {public void test() {testTransactional();}@Transactionalpublic void testTransactional() {}}

解决方法

启动类加@EnableAspectJAutoProxy

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;@SpringBootApplication
@EnableAspectJAutoProxy //必须加注解
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}
}

修改后代码


import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component
public class TestBean {public void test() {//事务想要生效,还得利用代理来生效!!!//获取代理对象(proxy)// 启动类加上 @EnableAspectJAutoProxyTestBean proxy = (TestBean) AopContext.currentProxy();proxy.testTransactional();}@Transactionalpublic void testTransactional() {}}
  1. 出现异常手动回滚
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;@Component
public class TestBean {@Transactionalpublic void testTransactional(User user) {try {save(user);} catch (Exception ex) {ex.printStackTrace();// 手动标记回滚TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}}private void save(User user) {}}

集合、接口中的坑

对象一定要初始化!

User user=null;

避免空指针

  1. 方法的返回值为空
  2. 方法、属性的调用者为空
  3. 对象未初始化
  4. 数组、集合未初始化
  5. 自动拆箱导致的空指针
  6. 方法传入的参数为空要判断!!
  public static void main(String[] args) {List userList = null;testFor(userList);}public static void testFor(List users) {if (users == null) return;for (User user : users) {}}
  1. 操作引用类型的属性时,一定要记得判空!
if(user==null) {return xxx;
}
if(user!=null){//业务代码
}

for循环

  1. 使用 原始 for循环
for (int i = 0; i < 100; i++) {  }
  1. 使用增强for循环
//注意判空
for (User user : users) { }

要好好判等!

  1. 基本数据类型 直接用==比较
  2. 引用数据类型 用equals判断时,要重写equals方法

抽象类与接口

  1. 抽象类是模板不能被实例化
  2. 抽象类中不能有static和final!
  3. 接口中的默认方法不需要实现,可以由实现类直接调用
  4. 接口中只能是常量,抽象类可以 有普通变量
  5. 类可以 实现多个接口,只能 继承一个抽象类
  6. 接口 还可以继承多个接口!
  7. 接口中可以有默认方法和静态方法
  8. 抽象类使用extends,接口用implements

BigDecimal等大数

浮点数的计算,使用字符串初始化!!

使用 BigDecimal 表示和计算浮点数,且务必使用字符串的构造方法来初始化 BigDecimal

//加
System.out.println(new BigDecimal("0.1").add(new BigDecimal("0.2")));
//减
System.out.println(new BigDecimal("1.0").subtract(new BigDecimal("0.8")));
//乘
System.out.println(new BigDecimal("4.015").multiply(new BigDecimal("100")));
//除
System.out.println(new BigDecimal("123.3").divide(new BigDecimal("100")));//BigDecimal.valueOf() 初始化也可以!
System.out.println(BigDecimal.valueOf(1.0).subtract(BigDecimal.valueOf(0.8)));
//0.2

在这里插入图片描述

比较浮点数相等compareTo不用equals

//Returns:
//-1, 0, or 1 as this BigDecimal is numerically less than, equal to, or greater than val.
System.out.println(new BigDecimal("1.0").compareTo(new BigDecimal("1"))==0);
//trueSystem.out.println(new BigDecimal("1.0").equals(new BigDecimal("1")))
//结果:false

数值溢出问题

//long的最大值
System.out.println(Long.MAX_VALUE);
// +1 之后溢出,成为long的最小值-9223372036854775808
System.out.println(Long.MAX_VALUE+1==Long.MIN_VALUE);
//long的最大值+1, 使用 BigInteger 防止溢出!!
System.out.println(new BigInteger(String.valueOf(Long.MAX_VALUE)).add(BigInteger.valueOf(1)));

在这里插入图片描述

精度问题

	// scale 需要与小数位匹配BigDecimal bigDecimal = new BigDecimal("12.222");// 若设置的精度 比 以前的高,会自动补0// BigDecimal res = bigDecimal.setScale(12);//ROUND_HALF_UP 为四舍五入BigDecimal res = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP);System.out.println(res);

除法除不尽抛异常

        //除不尽 会抛异常
//        System.out.println(new BigDecimal("2").divide(new BigDecimal("3")));System.out.println(new BigDecimal("2.0").divide(new BigDecimal("3"), 2, BigDecimal.ROUND_HALF_UP));

在这里插入图片描述

long类型数字加上L,float加上F

日期

日期计算LocalDateTime

代码

  //时间格式化器DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");//获取 当前时间LocalDateTime localDateTime = LocalDateTime.now();System.out.println(localDateTime);System.out.println(formatter.format(localDateTime));//指定 时间LocalDateTime _1970 = LocalDateTime.of(1970, 1, 1, 0, 0, 0);System.out.println(_1970);//时间格式化器LocalDateTime---->String,调用format方法String _1970_str = formatter.format(_1970);System.out.println(_1970_str);// 获取该月的第几天int dayOfMonth = localDateTime.getDayOfMonth();System.out.println(dayOfMonth);// 将字符串解析为 LocalDateTime对象LocalDateTime _2010 = LocalDateTime.parse("2010-01-01 00:00:00", formatter);System.out.println(_2010);//1970年1月1日 +10日LocalDateTime _1970_plus10days = _1970.plusDays(10);System.out.println(_1970_plus10days);//1970年1月1日 -10日LocalDateTime _1970_minus10days = _1970.minusDays(10);System.out.println(_1970_minus10days);//修改1970年1月1日的DayOfMonth,即为1970年1月20日LocalDateTime _1970_setDayofMonth_10 = _1970.withDayOfMonth(20);System.out.println(_1970_setDayofMonth_10);//LocalDateTime转为LocalDate--->只有年月日// LocalTime--->只有时分秒LocalDate localDate = localDateTime.toLocalDate();System.out.println(localDate);//1970-1-1 00:00:00_1970 = LocalDateTime.of(1970, 1, 1, 0, 0, 0, 0);// 1970年到 现在的时间间隔// 年,一共多少个月,与天数,天数 仅仅在31天Period _1970_now_period = Period.between(_1970.toLocalDate(), localDateTime.toLocalDate());System.out.println(_1970_now_period.toTotalMonths());System.out.println(_1970_now_period.getDays()); //22-1System.out.println(_1970_now_period.getYears());//获取两个时间的间隔,总的天数,Duration between = Duration.between(_1970, LocalDateTime.now());System.out.println(between.toHours());System.out.println(between.toDays());System.out.println(between.toMillis() - 28800000L);System.out.println(System.currentTimeMillis());//isAfter(xx)在xx之后//isBefore(xx)在xx之前System.out.println(localDateTime.isAfter(_1970));System.out.println(localDateTime.isBefore(_1970));

SimpleDateFormat的使用 以及线程不安全

  1. 变为局部变量
  2. ThreadLocal
		//new 出来一个 格式化器SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");// 当前时间转为字母串String now = format.format(new Date());System.out.println(now);// 将字符串转为时间String date = "2022-12-30";try {Date parseDate = format.parse(date);System.out.println(parseDate);} catch (ParseException e) {e.printStackTrace();}// 时间转为 时间戳long time = format.parse(date).getTime();System.out.println(time);System.out.println(System.currentTimeMillis());

时间格式转换

pom

org.springframework.bootspring-boot-starter-web

org.projectlomboklombok

cn.hutoolhutool-all5.8.7

org.apache.httpcomponentshttpclient4.5.13

DateConverter


import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;import java.text.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;@Component
public class DateConverter extends SimpleDateFormat implements Converter {public static final List FORMARTS = new ArrayList<>();static {FORMARTS.add("yyyy-MM");FORMARTS.add("yyyy-MM-dd");FORMARTS.add("yyyy-MM-dd HH:mm");FORMARTS.add("yyyy-MM-dd HH:mm:ss");}@Overridepublic Date convert(String source) {String value = source.trim();if ("".equals(value)) {return null;}if (source.matches("^\\d{4}-\\d{1,2}$")) {return parseDate(source, FORMARTS.get(0));} else if (source.matches("^\\d{4}-\\d{1,2}-\\d{1,2}$")) {return parseDate(source, FORMARTS.get(1));} else if (source.matches("^\\d{4}-\\d{1,2}-\\d{1,2} {1}\\d{1,2}:\\d{1,2}$")) {return parseDate(source, FORMARTS.get(2));} else if (source.matches("^\\d{4}-\\d{1,2}-\\d{1,2} {1}\\d{1,2}:\\d{1,2}:\\d{1,2}$")) {return parseDate(source, FORMARTS.get(3));} else if (isTimestamp(source)) {//long 时间戳转换return parseDate(source, FORMARTS.get(3));} else {throw new IllegalArgumentException("Invalid boolean value '" + source + "'");}}/*** 格式化日期** @param dateStr String 字符型日期* @param format  String 格式* @return Date 日期*/public Date parseDate(String dateStr, String format) {Date date = null;//long 时间戳转换if (isTimestamp(dateStr)) {long time = Long.parseLong(dateStr);date = new Date(time);}try {DateFormat dateFormat = new SimpleDateFormat(format);date = dateFormat.parse(dateStr);} catch (Exception e) {}return date;}public static boolean isNumeric(String str) {Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");return pattern.matcher(str).matches();}public static boolean isTimestamp(String str) {return str != null && str.length() == 13 && isNumeric(str);}@Overridepublic Date parse(String source) throws ParseException {Date convert = this.convert(source);return convert;}//设置所有接口返回的时间为毫秒级的时间戳@Overridepublic StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition pos) {StringBuffer stringBuffer = new StringBuffer("" + date.getTime());return stringBuffer;
//        return super.format(date, toAppendTo, pos);}}

DateConverterConfig

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;@Configuration
public class DateConverterConfig {@Autowiredprivate DateConverter dateConverter;@Bean@Primarypublic ObjectMapper objectMapper() {ObjectMapper objectMapper = new ObjectMapper();objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);objectMapper.configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true);objectMapper.setDateFormat(dateConverter);return objectMapper;}
}

支持这四种格式 + 13位时间戳

在这里插入图片描述
返回的时间为毫秒级的时间戳

反射、序列化

反射

  1. 方法是基本类型时,反射 获取 Method的参数类型也必须一致,不能是 其包装类!!
  2. 如果 调用的方法 属于当前对象的父类,那么getDeclaredMethod获取 不到Method

Serializable

  1. 类中 存在引用对象,引用对象也实现序列化,该类 才可实现序列化
  2. 子类实现Serializable接口,父类存在 无参构造方法,子类可以序列化

深拷贝

涉及到的 所有对象都必须实现Serializable接口

	 @Overrideprotected User clone() throws CloneNotSupportedException {User user = null;try {ByteArrayOutputStream baos = new ByteArrayOutputStream();//ObjectOutputStream是包装流ObjectOutputStream oos = new ObjectOutputStream(baos);//写入到 baos流中oos.writeObject(this);//将流序列化成对象ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bais);User o = (User) ois.readObject();} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}return user;}

相关内容

热门资讯

demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
阿西吧是什么意思 阿西吧相当于... 即使你没有受到过任何外语培训,你也懂四国语言。汉语:你好英语:Shit韩语:阿西吧(아,씨발! )日...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
阿西吧是什么意思 阿西吧相当于... 即使你没有受到过任何外语培训,你也懂四国语言。汉语:你好英语:Shit韩语:阿西吧(아,씨발! )日...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...