文章目录
1. union与union all的区别
在 Java 中,union 和 union all 是 SQL 查询语句中用于合并两个查询结果集的关键字。它们的区别如下:
union: union 关键字用于合并两个查询的结果集,并去除重复的行。如果两个查询的结果集中有相同的行,则只会返回一次。
union all: union all 也用于合并两个查询的结果集,但不会去除重复的行。它会简单地将两个结果集中的所有行都合并在一起,包括重复的行。
因此,union all 的执行效率通常比 union 高,因为不需要去除重复行。但如果你需要确保结果中没有重复的行,应该使用 union。
2. char和varchar的区别
3. 数据库三大范式
在数据库设计中,有三个重要的范式规则,被称为数据库的三大范式(Normalization):
第一范式(1NF):确保每个列具有原子性。每个表格中的列都应该是不可分割的最小数据单位,不允许将多个值放在一个列中。
第二范式(2NF):确保非主键列完全依赖于主键。即,表格中的非主键列必须完全依赖于主键,而不是依赖于主键的某个部分。
第三范式(3NF):确保非主键列之间没有传递依赖。即,表格中的非主键列之间不应该相互依赖,也就是说不应该存在传递依赖关系。
遵循这些范式可以提高数据库的规范性、减少数据冗余和错误,并提高数据的一致性和查询性能。但是需要注意的是,范式化并不一定适合所有情况,在某些特定的场景下可能需要根据具体需求做出一些冗余或优化的设计。
4. 谈谈你对SpringAOP的理解
5. AOP的代理有几种方式
在 Spring AOP 中,实现切面的方式主要有两种:基于 JDK 动态代理和基于 CGLIB 代理。具体来说,它们的实现方式如下:
基于 JDK 动态代理
基于 JDK 动态代理的切面是通过 Java 反射机制实现的。当目标对象实现了至少一个接口时,Spring 就会使用 JDK 动态代理来生成代理对象;否则,Spring 将会使用 CGLIB 代理。
JDK 动态代理的原理是基于目标对象实现了接口这一特点,通过创建一个实现 InvocationHandler 接口的代理类来实现 AOP 的功能。该代理类包含了目标对象和通知逻辑,当调用代理对象的方法时,实际上是调用了 InvocationHandler 接口的 invoke 方法,因此可以在该方法中执行通知逻辑。
基于 CGLIB 代理
基于 CGLIB 代理的切面是通过继承目标对象的方式实现的。当目标对象没有实现任何接口时,Spring 就会使用 CGLIB 代理来生成代理对象。
CGLIB(Code Generation Library)是一个强大的、高性能、代码生成库,它可以在运行时动态地生成指定类的子类,从而实现继承目标对象的代理。CGLIB 代理的原理是通过生成一个目标对象的子类,并在子类中重写需要增强的方法,从而实现切面的功能。
总的来说,Spring AOP 的代理方式有两种:基于 JDK 动态代理和基于 CGLIB 代理。JDK 动态代理适用于目标对象实现了接口的情况,而 CGLIB 代理则适用于目标对象没有实现接口的情况。
6. Spring的通知类型有哪些
在 Spring AOP 中,有以下几种通知类型:
1.前置通知(Before Advice):在目标方法执行之前执行的通知。可以在该通知中进行一些预处理操作。
2.后置通知(After Advice):在目标方法执行之后(无论是否发生异常)执行的通知。可以在该通知中进行一些后续处理操作。
3.返回通知(After Returning Advice):在目标方法成功执行并返回结果后执行的通知。可以在该通知中获取目标方法的返回值,并进行相应的处理操作。
4.异常通知(After Throwing Advice):在目标方法抛出异常后执行的通知。可以在该通知中捕获目标方法抛出的异常,并进行相应的异常处理。
5.环绕通知(Around Advice):是最强大和最灵活的通知类型。环绕通知包围目标方法的整个执行过程,在方法调用前后都可以添加自定义的逻辑。可以控制目标方法是否执行,以及在执行前后进行一些额外的操作。
这些通知类型可以根据需要选择使用,或者组合使用,来实现对目标方法的不同切面操作。例如,可以在前置通知中记录日志,后置通知中清理资源,返回通知中进行结果处理,异常通知中进行异常处理等。通过配置这些通知,我们可以实现横切关注点的功能,提高代码的可维护性和复用性。
7. Spring事务传播行为有几种
在 Spring 中,事务传播行为(Transaction Propagation Behavior)指的是在方法调用时,当前方法与已存在的事务之间的关系。Spring 提供了以下几种事务传播行为:
1.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则新建一个事务。这是最常见的传播行为,也是默认的传播行为。
2.PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式执行。
3.PROPAGATION_MANDATORY:强制使用当前事务,如果当前没有事务存在,则抛出异常。
4.PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,则挂起该事务,并且新建一个事务;如果当前没有事务,则新建一个事务。
5.PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,则将事务挂起。
6.PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
7.PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务中执行;如果当前没有事务,则新建一个事务。
通过设置不同的事务传播行为,我们可以控制事务在方法调用过程中的行为,确保事务的一致性和完整性。根据业务需求和场景选择合适的事务传播行为是很重要的,可以避免事务操作中出现意外情况。
8. 浅拷贝和深拷贝区别
浅拷贝(Shallow Copy)和深拷贝(Deep Copy)是在进行对象复制时常见的两种方式,它们之间有以下区别:
浅拷贝(Shallow Copy):
浅拷贝会创建一个新的对象,但是新对象中的字段值是对原始对象中字段的引用。
换句话说,浅拷贝只复制对象本身以及对象中的基本数据类型字段,而对于对象内部的引用类型字段,则复制它们的引用而不是实际的对象。
因此,如果修改了浅拷贝后的对象中的引用类型字段所指向的对象,那么原始对象中对应字段的值也会受到影响。
深拷贝(Deep Copy):
深拷贝会创建一个新的对象,并且递归地复制对象本身以及对象中所有的引用类型字段,确保复制出的对象与原始对象完全独立,互不影响。
换句话说,深拷贝会复制对象本身以及对象内部所有的引用类型字段,而不仅仅是复制它们的引用。
总的来说,对于浅拷贝来说,复制的是对象本身以及对象中的基本数据类型字段,而对于引用类型字段只是复制了引用;而深拷贝则会递归复制对象本身以及对象内部所有的引用类型字段,确保复制出的对象是完全独立的。在实际开发中,根据需求选择合适的拷贝方式很重要,以避免出现意外的数据共享问题。