1. mysql REGEXP正则查询
mysql也可以使用正则查询。虽然不常用,但是要知道有这么个东西。MySQL中的REGEXP是一个函数,用于在表达式中匹配字符串。它可以在SELECT、WHERE、HAVING等语句中使用。
REGEXP函数的语法如下:
expr REGEXP pattern 其中,expr是要匹配的字符串,pattern是一个包含正则表达式的字符串。
例如,如果要查找包含“abc”子串的所有字符串,可以使用以下代码:
SELECT * FROM table WHERE column REGEXP 'abc';
使用REGEXP函数可能会导致性能低下,因为它需要对每个符合条件的记录执行一个正则表达式匹配。如果表中的记录数很大,这个过程可能会很慢。因此,为了获得更好的性能,最好避免在大型表上使用REGEXP功能,并使用其他替代方案来实现相同的目标,例如LIKE运算符或全文搜索引擎。
2. java8之前的永久代和8之后的元空间
在 Java 8 之前,Java 运行时环境会将程序中加载的类、方法区(Method Area)数据、字符串常量池和一些其他的 Java 运行时环境内部数据(例如虚拟机内部常量池)存储在永久代(PermGen)里面。
具体来说,永久代里面存储的内容包括:
- 加载的类及其静态字段和方法;
- 常量池,包括字符串常量和类常量;
- JIT 编译器编译后的代码;
- 动态生成的代理类以及相关的字节码和反射相关的动态调用;
- 一些需要类加载器在加载类的时候进行特殊处理的数据结构;
- 可能还会包含一些 JVM 内部使用的数据结构,例如符号引用表等。
需要注意的是,永久代的大小只有在 JVM 启动时才被确定,并且不能动态地调整大小,因此如果不合理地设置了 PermGen 大小,就有可能会导致应用或者 JVM 崩溃。
在 Java 8 中,永久代已经被元空间(Metaspace)所取代,元空间与永久代不同之处在于,元空间不再是 JVM 堆内存的一部分,而是使用本机内存来存储类和方法信息。Metaspace 相对于永久代的重要改进是,它的内存空间不再是固定的,而是可以根据需要动态调整。因此,程序中加载的类和方法可以很好地适应内存需求的变化。
具体来说,Metaspace 里面存储的内容包括:
- 加载的类及其方法,与永久代中的内容类似;
- 类元数据,包括类名称、字段、方法、访问标志以及其他的一些元数据信息,这些信息用于 JVM 运行时解析方法调用、字段访问等操作;
- JIT 编译器编译后的代码,与永久代中的内容类似;
- 动态生成的代理类及其相关的字节码和反射相关的动态调用。
总的来说, Metaspace 存储的是 Java 运行时环境内部和应用所需要的重要信息,包括类信息、方法信息、常量池等。如果应用程序中加载的类或方法过多,就需要增加 Metaspace 的大小以满足需求。同时,如果内存不足,Metaspace 的大小也可以自动缩小,以便节约内存。
需要注意的是,尽管 Metaspace 可以根据需要动态调整大小,但是它仍然是有实际限制的。如果现有的内存无法满足 Metaspace 的需求,就会抛出 OutOfMemoryError。因此,在设置 Metaspace 的大小时,需要根据实际需求权衡内存和性能,并充分测试以确保 Metaspace 的稳定性和可靠性。
3. js打印图片
function printThisWindow(imgSrc) {
let iframe = document.createElement('IFRAME')
let doc = null
iframe.setAttribute('class', 'print-iframe')
iframe.setAttribute('style', 'position:absolute;width:0px;height:0px;left:-500px;top:-500px;')
document.body.appendChild(iframe)
doc = iframe.contentWindow.document
// 取一个不重复的方法名称,可以随机字符串
doc.___imageLoad___ = function (
) {
iframe.contentWindow.print()
if (navigator.userAgent.indexOf('MSIE') > 0) {
document.body.removeChild(iframe)
}
}
doc.write('<div style="height: 100%;width: 100%;">' + '<img src="' + imgSrc +'" style="max-height:100%;max-width: 100%;" onload="___imageLoad___()"/>' + '</div>')
doc.close()
iframe.contentWindow.focus()
}
4. 开发过程中在idea中tomcat配置了oss虚拟路径,打包之后怎么配置?
打开tomcat目录下的conf/Catalina/localhost,新建oss.xml文件,文件名对应要配置的虚拟路径,添加如下信息:
刚开始tomcat可能没有对应的文件夹,启动一下tomcat就有了
5. 什么是resuful风格,为什么要按照restful风格写接口?
RESTful风格是一种基于HTTP协议的架构风格,它强调使用统一的、有限的操作集合来操作资源。具体来说,它将资源抽象为URI(统一资源标识符),通过使用HTTP动词(GET、POST、PUT、DELETE等)来对资源进行操作,通过HTTP状态码来表示操作的结果。Restful风格主张以资源为中心,通过HTTP动词对资源进行操作,让服务端状态无状态,以及遵循REST原则,提供简单易懂的API接口。
按照RESTful风格写接口,能够让接口更加简单易懂,可读性更强,易于维护和管理。同时,RESTful接口也很容易与其他系统(如移动客户端、网页客户端等)进行集成和交互,可以提高接口的可扩展性,适应性和灵活性。此外,遵循RESTful风格还可以提升接口的性能和安全性,有助于减少不必要的交互和保护API接口免受恶意访问和攻击。
6. 什么是内存屏障?
内存屏障(Memory Barrier)是一种计算机系统中用于控制内存访问的指令。内存屏障可以确保在特定的时间点或者操作完成后,所有之前的内存操作都已经完成或者已经被刷新到内存中。
内存屏障分为两种类型:
1.读屏障(Read Barrier):确保一个线程能够读取到其它线程的最新数据。
2.写屏障(Write Barrier):确保一个线程更新的数据能够被其它线程及时看到。
内存屏障可以避免出现内存读取的竞态条件,同时也可以确保不同的CPU能够按照一定的顺序执行内存操作,从而避免出现数据不一致的情况。
7. synchronized锁什么?
synchronized关键字在Java中可以用来实现线程同步,确保多个线程对共享资源的访问是有序、按照一定的规则进行的,以避免数据竞争和数据不一致的问题。在Java中,synchronized关键字可以作用于不同的对象或者类:
- 对象锁:synchronized(obj) {} 会锁定obj对象,只有一个线程能够持有该对象的锁,从而在同一时刻只允许一个线程对该对象进行访问。
- 类锁:synchronized(Obj.class) {} 会锁定Obj类,只有一个线程能够持有该类的锁,从而在同一时刻只允许一个线程对该类的所有对象进行访问。
需要注意的是,不同线程对同一个对象的不同synchronized块会相互竞争锁,而不同线程对不同的对象的synchronized块不会相互竞争锁,因为它们锁定的是不同的对象。另外,synchronized方法默认会锁定当前对象,即this,因此对同一个对象中的synchronized方法和synchronized块会相互竞争锁。
8. 为什么私有ip常用的是c类
私有IP地址范围是由RFC 1918定义的。其中,10.0.0.0/8子网、172.16.0.0/12子网以及192.168.0.0/16子网是三个私有IP地址范围。在这三个IP地址范围中,192.168.x.x是C类IP地址范围,而10.x.x.x和172.16.x.x至172.31.x.x则是A类和B类IP地址范围。虽然这些IP地址范围都可以用来配置私有网络,但是C类IP地址范围更受欢迎的原因如下:
- IP地址数量:C类IP地址范围可以提供256 x 256 = 65,536个IP地址,比A类和B类IP地址范围要少得多,但正好适用于一般中小企业和家庭网络使用。
- 管理方便:C类IP地址范围的地址分配更加灵活,被分配的地址数量相对较少,更容易管理和控制。
- 兼容性好:C类IP地址范围在几乎所有网络设备和操作系统中都得到支持,并且可以方便地和公共网络进行交互,因此更容易在公司和家庭中使用。
9. java怎么根据hashmap中的字段生成图片
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import javax.imageio.ImageIO;
public class HashMapToImageDemo {
public static void main(String[] args) {
// 创建一个HashMap并添加一些字段
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("name", "张三");
hashMap.put("age", "28");
hashMap.put("gender", "男");
// 调用generateImage方法生成图片
generateImage(hashMap);
}
public static void generateImage(HashMap<String, String> hashMap) {
// 创建一个位图并设置长、宽以及类型
int width = 400;
int height = 200;
BufferedImage image = new BufferedImage(
width, height, BufferedImage.TYPE_INT_RGB);
// 获取Graphics2D上下文
Graphics2D g2 = image.createGraphics();
// 设置背景色、字体颜色和字体
g2.setColor(Color.WHITE);
g2.fillRect(0, 0, width, height);
g2.setColor(Color.BLACK);
// 汉字千万不要用Arial,要用:宋体
g2.setFont(new Font("Arial", Font.BOLD, 16));
// 循环遍历HashMap中的字段,将它们写入图像中
int i = 1;
for (String key : hashMap.keySet()) {
g2.drawString(key + ": " + hashMap.get(key),
20, 20 * i++);
}
// 释放上下文,保存图像
g2.dispose();
try {
ImageIO.write(image, "jpg", new File("hashmap.jpg"));
System.out.println("Image has been generated successfully!");
} catch (IOException e) {
System.out.println("Image could not be generated!");
e.printStackTrace();
}
}
}
10. Graphics2D的drawImage方法,怎么把一个BufferedImage画进去?
需求是生成一个二维码,加到图片里。二维码用了QRCode生成
Graphics2D的drawImage方法可以用于在当前的Graphics2D上下文中从一个 BufferedImage 中绘制出指定的矩形区域。该方法有多个重载形式,其中最常用的是以下形式:
drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer);
这个方法的参数可以依次解释如下:
- img:要绘制的图像,这里可以传入一个 BufferedImage 对象;
- x:要绘制的图片的 X 坐标;
- y:要绘制的图片的 Y 坐标;
- width:要绘制的图片的宽度,可以缩放图片的宽度;
- height:要绘制的图片的高度,可以缩放图片的高度;
- bgcolor:如果需要填充一些背景色的话,指定要使用的背景色。如果不需要可以传入null。
- observer:ImageObserver 对象,用于观察图片是否加载完毕。
下面是一个示例,演示如何使用 Graphics2D 的 drawImage 方法将一个 BufferedImage 绘制出来:
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class ImageDemo {
public static void main(String[] args) throws IOException {
BufferedImage img = ImageIO.read(new File("path/to/image.jpg")); // 读取图片
BufferedImage result = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB); // 创建新的 BufferedImage 对象
Graphics2D graphics = result.createGraphics(); // 创建 Graphics2D 对象
graphics.drawImage(img, 0, 0, img.getWidth(), img.getHeight(), null); // 将图片绘制在 Graphics2D 上下文中
graphics.dispose(); // 释放资源
ImageIO.write(result, "jpg", new File("path/to/result.jpg")); // 将绘制后的 BufferedImage 保存为文件
}
}
11. 做事一定要记录
今天调打印图片参数,上去就调整参数打印,没有对打印参数和结果做记录,导致想退回某个版本费了老大劲,重新试了一遍才好。浪费生命,以后一定要记录,节约生命
12. java的final用于基本类型和引用类型的区别
- final基本类型
当一个变量被声明为final基本类型之后,这个变量的值不能修改。
- final引用类型
当一个变量被声明为final引用类型时,该变量的引用(即地址)不能修改。但是变量引用对象内部的状态是可以修改的。
13. mysql [ERR] 1067 - Invalid default value for 'CREATED_'
修改全局sql_mode(管用,但是治标不治本,重启就无效了) set @@global.sql_mode=(select replace(@@global.sql_mode,'NO_ZERO_IN_DATE,NO_ZERO_DATE',''));
治本:
这个错误通常是因为 MySQL 新版本对于 datetime 数据类型的默认值要求更加严格,如果 datetime 字段定义了默认值为 "0000-00-00 00:00:00",则会提示 "Invalid default value for '字段名'" 的错误。
解决这个问题可以通过修改 MySQL 配置文件来实现。具体步骤如下:
- 找到 my.cnf(或 my.ini) 配置文件,一般位于 MySQL 安装目录下的 /etc 或 /bin 目录下。
- 在配置文件中找到
sql_mode 配置项,如果没有则添加,例如:
sql_mode=NO_ENGINE_SUBSTITUTION
或
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
其中,NO_ENGINE_SUBSTITUTION 表示使用不存在的存储引擎时抛出错误,STRICT_TRANS_TABLES 表示在插入或更新记录时,如果列类型不匹配,则抛出错误。
- 保存配置文件并重启 MySQL 服务,使用以下命令可以查看是否生效:
SHOW VARIABLES LIKE 'sql_mode';
执行成功后应该看到返回的 sql_mode 中包含了刚刚修改的配置项。
另外,如果是已经存在的表结构中包含了 datetime 类型的默认值为 "0000-00-00 00:00:00",可以通过执行以下 SQL 语句来删除该默认值:
ALTER TABLE table_name MODIFY column_name DATETIME NULL DEFAULT NULL;
其中,table_name 表示表名,column_name 表示 datetime 类型的字段名。
执行成功后,该字段的默认值就变成了 NULL,即可避免由于默认值不合法导致的错误。
14. SpringMvc上传文件遇到重复读取InputStream的问题
最好先 检查当前输入流是否支持 mark 和 reset 操作:inputStream.markSupported()
InputStream inputStream = new ByteArrayInputStream(bytes); inputStream.mark(0); String md5 = MD5Utils.getMD5(inputStream); inputStream .reset();
15. MultipartFile 去获取inputStream,出现了第二次再次获取流游标没有归0的问题
MultipartFile 获取inputstream之后明明调用了close方法,可是仍旧需要mark然后reset下次才能正常使用inputstream。
debug显示pos不置0
调用close()方法会关闭流并释放相应的资源,但是并不会对流的指针进行重置。因此,如果在流关闭后再次获取流时会报错: Stream closed。为了避免这个问题,需要在获取inputStream之前,先使用mark()方法标记流指针的位置,然后在需要重置指针时使用reset()方法。
InputStream是Java标准库中用于读取数据的抽象类。它的子类实现了read()方法,用于读取流中的数据。
InputStream类中有三个非常重要的变量:buf、pos和count。
- buf:输入缓冲区,即从流中读取数据的缓存区。
- pos:指针位置,即下一个要读取的字节在缓冲区中的位置。
- count:缓冲区的长度,也就是当前可用的数据长度。
当我们调用InputStream对象的read()方法时,它会首先从缓冲区中读取数据,如果缓冲区为空或者已经读取完毕,就会向输入流中读取数据,并将读取到的数据放入缓冲区中。然后,pos指针会移动到下一个要读取的位置,count会减去已经读取的数据长度。
如果要读取的数据长度超过了缓冲区的长度,那么pos指针会被置为0,count会被置为0,表示缓冲区已经被清空,并且下一次读取数据时会直接从输入流中读取数据。需要注意的是,在使用InputStream时,我们应该避免直接访问buf、pos和count这些字段,而应该调用read()方法来读取数据,避免出现指针位置或数据长度的错误。
16. web.xml配置文件中transport-guarantee有什么作用?
有个同事遇到问题,他下载的一个老项目起不来了,idea弹窗说打不开对应的链接,一开始以为是配置文件的问题,但是百思不得其解,最终我决定从头捋一遍,从登录流程入手。
结果一旦方法用对了,得到结果就在一瞬间,在两分钟内我就定位到了问题。凡事多问两个为什么,答案就明了了
问题的原因是web.xml中配置了transport-guarantee 为CONFIDENTIAL,我改成NULL就ok了
在Java Web应用程序中,transport-guarantee用于指定客户端和服务器之间的连接的安全级别。它可以设置为NONE、INTEGRAL或CONFIDENTIAL。具体作用如下:
- NONE:表示不提供安全套接字层(SSL)连接,所有数据以明文形式发送。
- INTEGRAL:表示提供安全套接字层连接,但不进行加密操作。“INTEGRAL”确保所传输的数据未被篡改,但不提供加密保障。
- CONFIDENTIAL:表示提供安全套接字层连接,并对所传输的数据进行加密保护。这是一种最高级别的保护级别。
通常,transport-guarantee的设置是在web.xml文件中进行的。在应用程序中,如果要确保敏感数据(如密码和信用卡号码)的安全传输,则需要将transport-guarantee设置为CONFIDENTIAL。
顺变复习一下: HTTPS就是HTTP协议加上SSL(Secure Sockets Layer)/TLS(Transport Layer Security)协议。HTTPS是一种安全的HTTP通信协议,它使用SSL/TLS协议对数据进行加密传输,从而可以保护数据在传输过程中的机密性和完整性。当你使用HTTPS访问一个网站时,浏览器和服务器之间建立起了一条加密的通信隧道。通信的数据在传输过程中被加密,不容易被窃取和篡改。此外,HTTPS还可以验证网站的真实性,避免用户被欺骗和攻击。因此,对于需要保护用户敏感信息的网站,如在线银行、电子商务网站等,都需要使用HTTPS协议来加强安全性。
17. spring框架中,如果一个类没有交给spring管理,那么可以在类中使用@Resource或者@Autowired来注入对象吗
如果一个类没有交给Spring管理,那么无法在类中使用 @Resource、@Autowired注解来注入依赖项。因为 @Resource、@Autowired 是一种依赖注入 (DI) 注解,它依赖于 Spring 框架对类的管理和实例化。
如果您想在类中使用 @Resource、@Autowired 进行依赖注入,您需要将该类交给 Spring 管理。这可以通过在配置文件中声明该类的 bean 来实现,或者通过在类上添加 @Component 或其他相关的 Spring 注解来实现自动扫描和组件扫描。
因此,您需要确保您的类已被 Spring 管理,然后才能在类中使用 @Resource、@Autowired 进行依赖注入。
18. spring的InitializingBean
InitializingBean是Spring提供的一个用于在Bean实例化后进行初始化的接口。它只有一个方法afterPropertiesSet(),用于在Bean属性设置完成后执行初始化工作。
使用方法:
- 实现InitializingBean接口
- 重写afterPropertiesSet()方法,在该方法中实现对Bean的初始化工作
举个例子:
public class MyBean implements InitializingBean {
private String name;
@Override
public void afterPropertiesSet() throws Exception {
// 对name进行初始化
this.name = "MyBean";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
在使用该Bean时,Spring会先实例化该Bean,然后执行afterPropertiesSet()方法进行初始化,最后将该Bean返回给使用者。
使用该接口的优点是,可以保证Bean在实例化完成后进行初始化,避免了在Bean中使用构造方法时初始化失败的问题。同时,在Bean的初始化过程中,也可以保证依赖的属性已经被注入完成,便于进行初始化工作。
19. Java的inputstream.available天坑!!!
有个方法写出文件用到了available,我写完测试可以写出,但是一打包就不行了,最后发现是available的问题。。。
Java的InputStream是字节输入流的抽象类,它提供了读取字节流的方法。InputStream的available()方法用于返回InputStream中还没有读取的字节数。
但是,InputStream的available()方法并不能保证下一次读取数据时一定能读取到这些字节,因为在读取的过程中,可能会发生各种意外情况,比如数据被某些程序占用,网络中断等等。因此,对于可用字节的读取和使用,需要在读取数据时实时判断InputStream的available()方法,并且进行相应的异常处理。
虽然InputStream.available()方法在一些场景下可能会有一定的帮助,但需要注意以下几点:
- 可用字节数不一定等于剩余字节数:available()方法返回的是可以从输入流中读取的字节数,通常可以用来判断输入流中是否还有剩余的数据可供读取。但需要注意的是,实际上并不是所有的输入流都能准确地返回正确的字节数。例如,对于一些底层Socket的输入流,由于数据传输的特性,很可能会导致available()方法返回0或错误的字节数,从而使得程序不能准确地读取到输入流中的所有数据。
- 可能会阻塞线程:虽然InputStream.available()方法不会阻塞线程,但在一些情况下,如果程序在读取数据时调用了available()方法,而此时没有数据可供读取,程序会一直等待直到有数据可供读取,可能会导致线程阻塞。
- 不能确定是否还有数据可供读取:虽然InputStream.available()方法通常可以用来判断输入流中是否有剩余的数据可供读取,但并不能完全确定输入流是否还有数据。因此,在读取输入流中的数据时,最好使用特定的结束标记或固定长度的缓冲区进行读取,以确保可以完整地读取到输入流中的所有数据。
- 大规模数据传输不适用: InputStream.available()方法通常适用于小规模的数据传输,当涉及到大规模数据传输时,建议使用缓冲区配合读写操作,以减少IO读写的次数,提高程序性能。
总之就是天坑,尽量不要使用。
20. iptables和firewall区别
iptables和firewall都是Linux操作系统中的防火墙软件,能够过滤网络数据流,防止网络攻击等安全问题,提高网络安全性。
iptables是较为经典的防火墙,可以在命令行或者shell脚本中运行,针对IPv4或者IPv6网络协议进行工作,它将数据包发送到网络栈前就进行查找过滤,可以根据IP、端口、协议、mac地址等规则进行强大的过滤。使用iptables管理时,可以通过规则表来增加、删除、修改数据包过滤规则,使我们能够灵活地进行网络流量管理。最新版iptables提供支持路径请求跟踪、质量服务、NAT、和流量控制等众多功能,操作难度相对较高。
firewall是一款相对较新的防火墙软件,基于iptables开发,致力于提高操作易用性。firewall将过滤任务分为zone、service、port等,而不像iptables那样需要手动编写复杂的规则。firewall专门在Fedora, SLES, RHEL/CentOS等发行版中选用,它的工作方式是在用户空间中分零散的实现防火墙的基础功能。改善了防火墙的使用方便程度。
21. linux为什么需要./来执行sh文件
对于当前路径下的文件,使用./来指定路径,表示当前目录下的执行程序。例如,我们可以使用./script.sh来指定执行当前目录下的script.sh文件。
22. ssh默认端口是多少(常识)
SSH默认的端口是22。在Linux系统中,大多数SSH服务器默认使用22号端口来监听连接请求。在进行SSH连接时,如果没有指定端口号,SSH客户端会自动使用默认的端口22来进行连接。
23. 竞态条件
以前写的很多代码其实是有问题的,比如在类中定义一个map,然后去查询map中是否包含某个元素,根据包含与否进行不同的操作,这其实就是竞态条件,操作过程中数据可能会发生改变,具体会怎么执行是未知的。以后要注意,尽量在设计阶段就避免线程安全问题,毕竟正确性永远都排在第一位。
24. java开发使用spring框架,怎么在静态方法中拿到application.yml中的配置项?
通过注入的方式获取Environment对象
在静态方法中,我们可以通过注入的方式来获取Environment对象,进而获取配置信息。操作步骤如下:
首先,定义一个非静态类,注入Environment对象:
import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; import org.springframework.beans.factory.annotation.Autowired; @Component public class ConfigUtils { @Autowired private Environment environment; public String getValueFromYml(String key) { return environment.getProperty(key); } }
然后,通过静态方法来访问上述非静态类中的实例方法:
public static String getValueFromYml(String key) { ConfigUtils configUtils = applicationContext.getBean(ConfigUtils.class); return configUtils.getValueFromYml(key); }
在上述代码中,我们通过applicationContext.getBean()方法获取ConfigUtils类的单例实例,然后调用ValueFromYml方法获取配置信息。
需要注意的是,如果想要使用上述方式访问配置信息,需要先在Spring的配置类中注册ConfigUtils Bean:
@Configuration public class AppConfig { @Bean public ConfigUtils configUtils() { return new ConfigUtils(); } }
25. Environment 是什么
Environment是Spring Framework中的一个接口,用于描述当前应用程序运行环境的信息,包括了系统配置、环境变量等信息。通过Environment对象,我们可以访问应用程序配置文件(如application.yml)中的配置项信息。
在Spring应用程序中,我们可以通过依赖注入方式获取Environment对象,例如:
@Autowired private Environment environment;
使用Environment对象,我们可以获取配置信息,例如:
String value = environment.getProperty("my.key");
在上述代码中,我们通过getProperty()方法获取my.key这个配置项的值。
26. cpu为什么要对代码进行重排序
为了提高性能和效率。重排序可以使cpu在执行的过程中减少等待时间,因为在cpu执行的过程中,有些指令之间并没有依赖关系,可以同时或者交叉执行,从而可以节省时间。
另外,现代cpu执行速度很快,而内存和io速度相对较慢,相差好几个数量级。如果程序执行顺序遵循代码原始序列,则cpu则需要花费很多时间来等待内存或者io操作完成。重排序可以提高代码的并行度和缓存命中率,在减少cpu等待时间的同时也有助于提高整体性能。
27. as if serial语义是什么意思?
as if serial指的是一种操作的并行执行方式,它要求在并行执行的过程中,任何时候执行顺序和执行结果都必须与按照顺序执行时结果完全相同。
具体来说,在as if serial语义下,尽管操作是并行执行的,但是执行结果必须与单线程下执行相同。这意味着系统需要在执行操作之前对其进行一些检查和同步,以确保并行执行不会导致出现不一致的结果。
as if serial语义通常用于描述许多共享内存并行编程模型的保证。在这些模型中,多个线程的执行可以相互影响,但是通过采用as if serial语义,可以保证最终的执行结果与单线程时的结果相同。
28. spring 中的controller是单例的吗?
在 Spring 中,默认情况下,Controller 是单例模式的。 当 Spring 实例化一个 Bean 时,它会在 Bean 工厂中创建一个实例,并将该实例缓存起来以备将来使用。每次请求时,Spring 将重用相同的 Controller 实例,而不是创建一个新的实例。这意味着多个客户端可以共享同一个 Controller 实例,从而提高了系统的性能和效率。
但是,在某些情况下,您可能需要将 Controller 配置为非单例模式,例如,如果您的 Controller 包含状态信息,您不希望多个客户端共享同一个实例时。在这种情况下,您可以在 Controller 类上添加 @Scope 注解,并将其设置为 prototype。 总之,Spring 中的 Controller 默认是单例的,但您可以通过使用 @Scope 注解进行配置来更改其作用域。
29. 正则匹配数字
^((?!0)\d*|0)(\.\d+)?$
这个正则表达式的规则如下:
- 以^开头和$结尾,表示整个字符串必须符合条件。
- (?!0)\\d*表示非0开头的整数部分,即匹配所有不以0开头的整数或空串。这里使用了负向前瞻,确保整数部分不以0开头。另外,使用了\d*匹配任意个数字,可以匹配空串或任意位数的整数。
- 0表示0本身,即匹配0。
- (\\.\\d+)?表示小数部分,即匹配可选的小数部分。小数点和至少一位数字组成的小数部分,用\\.和\\d+表示,用()包裹起来表示可选部分,用?表示该部分可以出现0次或1次。
- |表示或,表示整数部分可以是非0开头的整数或者0本身。
- ^((?!0)\\d*|0)表示整个数字字符串,可以匹配非0开头的整数、0或带可选的小数部分的数字。
为什么要记录一下这玩意呢?主要是为了提醒自己,别有了chatgpt就不自己思考不学习了。我把需求给chatgpt让他生成正则出来,然后简单测试一下就不管了,结果一细测,直接就嘎了。这玩意生成的不一定对,用完要自己分辨。想做到顶级,自己还是得懂,不懂的话再好的语言模型也白搭,只能做出不入流的东西。
30. java中单引号和双引号的区别
- 单引号 ' ' 表示字符类型数据,在 ASCII 码表中对应一个整数值。
- 双引号 " " 表示字符串类型数据,使用一对双引号括起来的多个字符组成一个字符串。
ASCII 码是计算机中常用的字符编码方案之一,它将所有的字符映射为一个整数值,包括字母、数字、标点符号、控制字符等。ASCII 码共包含 128 个字符,使用 7 位二进制数编码。其中,0~31 为控制字符,32~127 为可打印字符。
ASCII 码中的字符与对应的整数值可以通过 Java 中的字符类型数据进行表示和转换。例如,字符 'A' 的 ASCII 码值为 65,可以定义一个字符变量并输出其对应的 ASCII 码值如下:
char c = 'A'; int ascii = (int)c; // 转换为整数类型表示ASCII码值 System.out.println(ascii); // 输出 65
还可以使用整数值初始化一个字符变量,该字符变量对应的字符即为其 ASCII 码表示的字符:
int ascii = 65; char c = (char)ascii; // 转换为字符类型 System.out.println(c); // 输出 A
31. 关于stream
今天用了一次streasm
// 使用Stream API过滤数据 List<Map<String, Object>> filteredList = list.stream() .filter(map -> set.contains((Integer) map.get("id"))) .toList();
但是在项目里不能这样写,.toList()不能直接用,而必须.collect(Collectors.toList()),看了java.util.stream.Stream接口,发现里面并没有toList接口。
.collect(Collectors.toList())方法实际上是一个终止操作,它会将Stream管道里的元素抽取出来,放到一个新的List作为结果返回。
总而言之,使用toList()方法可以使代码更加简洁。而且toList()方法只是Collectors.toList()方法的一个简写方式。
关于Stream操作会不会影响到原来的集合:使用 Stream API 对集合进行操作时,会生成一个新的 Stream 对象,对该 Stream 对象进行的操作仅仅是对于原数据的一次处理,不会修改原数据,也不会影响原数据的状态。在本例中,虽然使用了filter()方法对list进行了过滤操作,但其并不对原数据产生影响,仅仅是生成了一个新的List对象filteredList,其中包含过滤后的数据。原来的list对象仍然保持不变。这是Java Stream API的一大特性,让我们可以更加安全地对集合进行操作,不必担心对原数据的影响。
32. java把对象注入controller默认是单例的,指的是在一个controller里面单例,还是所有controller里单例
在Java中,将对象注入到Controller中默认是单例的,这意味着在一个Controller中注入的对象在整个应用程序中都是共享的,并且只存在一个实例。
当您在Spring MVC中创建一个控制器时,Spring会自动为您创建一个单例的ApplicationContext对象。如果您将一个对象注入到控制器中,那么该对象将会被视为单例,并且在整个应用程序中只会存在一个实例。
33. 关于mysql子查询
前几天遇到一个需求,有一个用户表和一个年度考核表,需要查出来所有用户,以及用户当年的考核信息,如果有当年的数据就展示当年的考核结果,没有的话就展示null。当时第一次写没考虑到有以前的数据直接判断是不是当年以及是不是null,最后的结果是如果用户今年之前有了考核数据,就会查不出用户的数据,因为他的考核数据不是当年也不是null。当时遇到这个问题想了一个小时竟然都没想到用子查询解决,后来还是请同时帮忙才解决。一句话点醒梦中人:如果表里只有23年的数据呢?
其实问题的原因还是自己对于子查询理解太少,导致遇到问题都想不起来还可以这么做。子查询其实可以理解为把子查询结果也作为一张表来使用,再配合join使用,简直所向披靡啊。还有就是chatgpt强不强,取决于用的人,如果用的人对于问题都很迷糊,chatgpt也帮助不大。解决这个问题就问了chatgpt好多,但我就是问不出来答案。
34. 设计模式:模板方法模式
模板方法模式是一种行为设计模式,它基于一个抽象类或接口,定义了一组操作步骤,其中某些步骤延迟到子类中实现。这种模式可以在不改变算法结构的情况下,使子类重新定义算法中的某些步骤。AQS就用到了
35. 关于synchronized锁什么和spring注入的对象
某个项目使用推特的雪花算法来生成表的主键id,获取方法使用synchronized修饰,而且在每次使用id的时候都去new对象,也就是说有多少个类使用,就需要new多少次。
由于synchronized修饰普通方法,锁的是对象,所以在多个类中同时获取id只要次数够多一定会获取到重复的id。如果一个表,再类a和类b中都有获取id,插入数据库会报错。
解决方案是,把生成id的类交给spring管理,然后不再new而是依赖spring注入。交给spring管理也有说法,不是简单@component就行的。首先是节点编号需要设置,这个我放在配置文件了,使用@value在方法参数里获取。第二点是关于spring使用哪个构造方法,默认是无参,我这肯定不使用无参,我在需要用的构造方法上使用了@Autowired,注意不能使用@Resource。
36. 雪花算法中workerId起什么作用
在雪花算法中,workerId 是用来标识工作机器的。由于雪花算法是为分布式系统设计的,在分布式系统中需要保证每个工作机器都能生成唯一的 id,因此需要为每个工作机器分配一个唯一的 workerId。
workerId 在 id 生成时主要起到两个作用:
- 避免冲突。
雪花算法中生成的 id 是由时间戳和序列号组成的,其中时间戳可以保证每个 id 在不同的时间内都是唯一的,但是如果多个工作机器使用相同的 workerId,就会导致它们生成的序列号可能相同,从而导致生成的 id 冲突。因此,每个工作机器需要有自己独立的 workerId,以避免这种冲突。
- 支持排序。
雪花算法生成的 id 是按照时间戳递增的,也就是说后生成的 id 肯定比先生成的 id 大。如果多个工作机器使用相同的 workerId,那么他们生成的 id 时间戳部分可能相同,从而无法保证排序。因此,每个工作机器需要有自己独立的 workerId,以支持排序。
如果使用 MAC 地址生成 workerId,那么更换 MAC 地址可能会导致生成的 id 冲突。因为雪花算法生成的 id 是由时间戳、workerId 和序列号组成的,其中 workerId 用于标识工作机器。如果一个工作机器的 MAC 地址发生了更改,那么它的 workerId 就会改变,从而可能导致其生成的 id 与之前已经生成的 id 冲突。
为了避免这种情况,可以采取以下措施:
- 避免随意更改 MAC 地址。
在生产环境中,工作机器的 MAC 地址应该是固定的,在部署时需要进行配置和管理。如果必须更改 MAC 地址,应该尽量避免在生成的 id 中使用 workerId,或者采用其他更加稳定的 workerId 生成方式。
- 使用动态生成
workerId 的方式。 在生产环境中,可以通过配置文件、数据库等方式来动态生成 workerId,从而支持动态扩容和更好的灵活性。这样即使工作机器的 MAC 地址发生了更改,也不会影响已经生成的 id。
37. spring中@Bean有什么作用?
在 Spring 中,@Bean 注解用于将某个方法的返回值声明为一个 bean,并交给 Spring 管理。通过 @Bean 注解,我们可以自定义创建和配置一个对象实例,并将其注入到其他需要使用它的地方。当 Spring 发现一个带有 @Bean 注解的方法时,它会调用该方法并将其返回值作为一个 bean 注册到应用程序上下文中
38. @Autowired和@Resource
- 作用对象不同。@Autowired和@Resource都可以用于成员变量或者 setter 方法上,而 @Autowired 可以用在构造方法上
- 使用方式不同。 @Autowired 注解默认是按照类型进行自动装配,如果多个组件类型匹配,可以使用 @Qualifier 注解通过名称进行限定。而 @Resource 注解则可以通过 name 或者 type 属性来指定要注入的组件。
- 来源不同。 @Autowired 注解属于 Spring 框架提供的注解,而 @Resource 注解属于 Java EE 标准提供的注解
@Resource如果指定了 name 属性,则会按照名称进行装配,必须要确保容器中存在与该名称对应的组件。如果未指定 name 属性,则会按照类型进行装配,必须要确保容器中只有一个与该类型对应的组件。
名称:@Resource(name = "snowflakeIdGenerator")
类型:@Resource(type = SnowflakeIdGenerator.class)
@Autowired private MyRepository repository; // 这叫做字段注入
39. mysql timestamp范围
坑的亚匹,出生年月用了这个,简直是折磨。一到范围外就报错了,淦
TIMESTAMP其范围从1970-01-01 00:00:01 UTC(协调世界时)到2038-01-19 03:14:07 UTC。4字节。
DATETIME类型的存储需求为8个字节,其中包含年、月、日、时、分和秒的信息。它的精度为秒级,可以存储从公元1000年到9999年的任何日期和时间。
40. 关于mysql的可重复度到底有没有解决幻读
首先要知道什么是幻读:幻读是指一个事务在读取某个范围内的记录时,另一个事务插入了一条新的记录,导致第一个事务再次读取该范围时,发现多了一条记录。幻读是一种与不可重复读和脏读不同的并发问题,它通常发生在可重复读隔离级别下。在可重复读隔离级别下,MySQL使用MVCC机制来避免脏读和不可重复读,但是无法避免幻读。为了避免幻读,可以使用串行化隔离级别,但是这会导致并发性能大幅下降。
以上是chatgpt给出的答案,其实他已经给我讲清楚了,并没有彻底解决。想测试出来需要一些特殊操作。我目前知道两个:
- 开启事务a,读取数据,获得结果a。开启事务b插入一条数据。在事务a对b插入的数据做更新操作,此时再次在事务a读取数据,这是你会发现会多了一条数据
- 步骤和上面都一样,只有一个步骤不一样,就是:在事务a对b插入的数据做更新操作,替换为在读数据sql最后加for update。在 SQL 语句的最后加上 FOR UPDATE,可以将查询结果集中的所有行都加上排他锁,防止其他事务对这些行进行修改,直到当前事务结束。这个语句通常用于实现悲观锁机制,即在事务中对某些数据进行修改时,先将这些数据加上排他锁,以防止其他事务对这些数据进行修改,从而保证数据的一致性和完整性。
41. mysql串行化
串行化隔离级别是最高的隔离级别,它要求所有事务都必须串行执行,即每个事务必须等待前一个事务执行完毕后才能开始执行。这意味着在串行化隔离级别下,只能有一个事务在任何时刻对数据库进行读写操作,其他事务必须等待当前事务执行完毕后才能开始执行。
因此,串行化隔离级别虽然可以避免所有的并发问题,包括脏读、不可重复读和幻读,但是它会严重影响数据库的并发性能,因为它会限制多个事务同时对数据库进行读写操作,从而导致系统的吞吐量大幅下降。