发表于: 2022-05-23 19:26:39

1 573



今天查询理解深度思考的问题


博客与知乎查询的资料:


1、JVM运行以及内存分配


什么是jre

JRE 是 JAVA 程序运行时需要的运行环境,就是说如果你光是运行 JAVA 程序而不是去搞开发的话,

只安装 JRE 就能运行已经存在的 JAVA 程序了。JDk、JRE 内部都包含 JAVA 虚拟机 JVM,

JAVA 虚拟机内部包含许多应用程序的类的解释器和类加载器等等。


什么是JVM?

JVM 是 Java Virtual Machine(Java 虚拟机)的缩写,它是由软件技术模拟出计算机运行的一个虚拟的计算机它是整个 java实现跨平台的最核心的部分,

所有的 java 程序会首先被编译为.class 的类文件,这种类文件可以在虚拟机上执行,也就是说 class 并不直接与机器的操作系统相对应,

而是经过虚拟机间接与操作系统交互,由虚拟机将程序解释给本地系统执行。JVM 是 Java 平台的基础,和实际的机器一样,它也有自己的指令集,

并且在运行时操作不同的内存区域。 JVM 通过抽象操作系统和 CPU 结构,提供了一种与平台无关的代码执行方法,

即与特殊的实现方法、主机硬件、主机操作系统无关。JVM 的主要工作是解释自己的指令集(即字节码)到 CPU 的指令集或对应的系统调用,

保护用户免被恶意程序骚扰。 通俗易懂的理解:JVM就是人与机器的翻译官,沟通的桥梁


每个JVM都主要包含:

方法区、Java堆、Java栈、本地方法栈、指令计数器及其他隐含寄存器


1、程序计数器

程序计数器(Program Counter Register) 是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里,字节码

解释器工作时就是通过改变这个计数器的值来选取下一条执行字节码指令。

每条线程都有一个独立的程序计数器。

如果执行的是java方法,这个计数器记录的是正在执行的虚拟机字节码指令地址。如果是native方法,计数器为空。


2、虚拟机栈

同样是线程私有,描述Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方

法出口等信息。一个方法对应一个栈帧。

局部变量表存放了各种基本类型、对象引用和returnAddress类型(指向了一条字节码指令地址)。其中64位长度long 和 double占两个局部变量空间,其他

只占一个。

规定的异常情况有两种:1.线程请求的栈的深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;2.如果虚拟机可以动态扩展,如果扩展时无法

申请到足够的内存,就抛出OutOfMemoryError异常。


3、本地方法栈

和Java虚拟机栈很类似,不同的是本地方法栈为Native方法服务。


4、Java堆

是Java虚拟机所管理的内存中最大的一块。由所有线程共享,在虚拟机启动时创建。堆区唯一目的就是存放对象实例。

堆中可细分为新生代和老年代,再细分可分为Eden空间、From Survivor空间、To Survivor空间。

堆无法扩展时,抛出OutOfMemoryError异常


5、方法区

所有线程共享,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

当方法区无法满足内存分配需求时,抛出OutOfMemoryError


在JVM 的上方是Java的基本类库和扩展类库以及它们的API,利用Java API编写的应用程序(application) 和小程序(Java applet).可以在任何Java平台上运行而无需考虑底层平台, 就是因为有Java虚拟机(JVM)实现了程序与操作系统的分离,从而实现了Java 的平台无关性。 JVM在它的生存周期中有一个明确的任务,那就是运行Java程序,因此当Java程序启动的时候,就产生JVM的一个实例;当程序运行结束的时候,该实例也跟着消失了。

API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,

目的是提供应用程序与开发人员基于某软件或硬件的以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。

类装载子系统:装载具有适合名称的类或接口②执行引擎:负责执行包含在已装载的类或接口中的指令

Java虚拟机(JVM)实现了程序与操作系统的分离



java 源码编译由以下三个过程组成:①分析和输入到符号表      ②注解处理      ③语义分析和生成class文件

最后生成的class文件由以下部分组成:

①结构信息:包括class文件格式版本号及各部分的数量与大小的信息

②元数据:对应于Java源码中声明与常量的信息。包含类/继承的超类/实现的接口的声明信息、域与方法声明信息和常量池

③方法信息:对应Java源码中语句和表达式对应的信息。包含字节码、异常处理器表、求值栈与局部变量区大小、求值栈的类型记录、调试符号信息


运行的过程图:





类加载器:


加载:类加载过程的一个阶段:通过一个类的完全限定查找此类字节码文件,并利用字节码文件创建一个Class对象

验证:目的在于确保Class文件的字节流中包含信息符合当前虚拟机要求,不会危害虚拟机自身安全。主要包括四种验证,文件格式验证,

元数据验证,字节码验证,符号引用验证。


准备:为类变量(即static修饰的字段变量)分配内存并且设置该类变量的初始值即0(如static int i=5;这里只将i初始化为0,至于5的值将在初始化时赋值),

这里不包含用final修饰的static,因为final在编译的时候就会分配了,注意这里不会为实例变量分配初始化,类变量会分配在方法区中,

而实例变量是会随着对象一起分配到Java堆中。


解析:主要将常量池中的符号引用替换为直接引用的过程。符号引用就是一组符号来描述目标,

可以是任何字面量,而直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。

有类或接口的解析,字段解析,类方法解析,接口方法解析。


初始化:类加载最后阶段,若该类具有超类,则对其进行初始化,

执行静态初始化器和静态初始化成员变量(如前面只初始化了默认值的static变量将会在这个阶段赋值,成员变量也将被初始化)。


----------------------------------------------------------------------------------------------------------

2、jdbc连接池原理及分析 


什么是连接池


1、连接池,首先从字面意思理解,这是一个偏正短语,左偏右正,重点在池这个字上。

 池(Pool)技术在一定程度上可以明显优化服务器应用程序的性能,提高程序执行效率和降低系统资源开销。

这里所说的池是一种广义上的池,比如数据库连接池、线程池、内存池、对象池等。其中,对象池可以看成保存对象的容器,

在进程初始化时创建一定数量的对象。需要时直接从池中取出一个空闲对象,用完后并不直接释放掉对象,

而是再放到对象池中以方便下一次对象请求可以直接复用。其他几种池的设计思想也是如此,池技术的优势是,

可以消除对象创建所带来的延迟,从而提高系统的性能。


2、数据库连接”是一种稀缺的资源,建立连接是一个费时的活动,每次都得花费0.05s~1s的时间,而且系统还要分配内存资源。

这个时间对于一次或几次数据库操作,或许感觉不出系统有多大的开销。可是对于现在的web应用,尤其是大型电子商务网站,

同时有几百人甚至几千人在线是很正常的事。在这种情况下,频繁的进行数据库连接操作势必占用很多的系统资源,网站的响应速度必定下降,

严重的甚至会造成服务器的崩溃。为了保障网站的正常使用,应该对其进行妥善管理。其实我们查询完数据库后,

不是关闭连接,而是暂时存放起来,当别人使用时,把这个连接给他们使用。就避免了一次建立数据库连接和断开的操作时间消耗。


Java中常用的数据库连接池有:

DBCP 、C3P0、BoneCP、Proxool、DDConnectionBroker、DBPool、XAPool、Primrose、SmartPool、MiniConnectionPoolManager及Druid等。


 连接池有什么好处

1.连接复用。通过建立一个数据库连接池以及一套连接使用管理策略,

使得一个数据库连接可以得到高效、安全的复用,避免了数据库连接频繁建立、关闭的开销。


2.共享资源,连接池的使用解决了资源频繁分配、释放所造成的问题的。

提供一套高效的连接分配、使用策略,最终目标是实现连接的高效、安全的复用。

------------------------------------------------------------------------------------------------------------------------

3、Mybatis有哪些常用标签?怎么使用标签来完成动态查询?


select 标签 

属性介绍:

  • id :唯一的标识符.
  • parameterType:传给此语句的参数的全路径名或别名 例:com.test.poso.User或user
  • resultType :语句返回值类型或别名。注意,如果是集合,那么这里填写的是集合的泛型,而不是集合本身(resultType 与resultMap 不能并用)
  • 示例:
<select id="selectPcByName" resultType="com.weixiao.Pc"
       parameterType="com.weixiao.Pc">
   select * from pc where 1=1
<if test="name!=null and name!=''">
       and name like concat('%',#{name},'%')
</if>
</select>



2 insert标签

属性介绍:

  • id :唯一的标识符
  • parameterType:传给此语句的参数的全路径名或别名 例:com.test.poso.User

示例:

<insert id="addUser" parameterType="com.weixiao.User">
   insert into user(name, type, school) value (#{name}, #{type}, #{school})
</insert>


3 delete标签

  • 属性同 insert

示例:

<delete id="delUserById" parameterType="integer">
   delete from user where id=#{id}
</delete>


4 update标签

属性同 insert


bean属性:用于指定依赖的Bean实例,可以是不同XML文件中的Bean

list标签:用于声明该依赖对象为一个list集合,其下用value和ref标签来指定list中的各值(基本、字符串、对象等)

set标签:用于声明该依赖对象为一个set集合,其用法与list标签相同。

map标签:用于声明该依赖对象为一个map集合,其下用entry标签来声明一个键值对

entry标签:用于声明map集合下的一个键值对,其下用key属性指明键,value/ref标签指明值

key属性:用于指明键值对中的键,它一般为字符串


•property标签用于输出值栈中的对象的属性值,使用value属性来指定要输出的对象属性,如果没有指定value属性,那么默认输出栈顶对象。

示例:

<property name="configLocation" value="classpath:mybatis-config.xml"/>


mappers 标签下有许多 mapper 标签,每一个 mapper 标签中配置的都是一个独立的映射配置文件的路径


示例:

<mappers>
   <!-- 映射器告诉MyBatis到哪里去找映射文件-->
   <mapper resource="com/mapper/UserMapper.xml"/>
   <mapper resource="com/mapper/PcMapper.xml"/>
</mappers>



mybatis中的动态SQL中的主要元素

1、 if 是mybatis动态SQL中的判断元素,这个有点类似于Java中的if语句,不同的是这里的if一般常常和test配合使用。

当用户传入的address不为null或者空字符串的时候,我就加上一个where条件,否则就什么条件都不加入。


2、 choose有点类似于Java中的switch,常常配合when和otherwise一起来使用。在查询条件中,

如果用户传来了id,那么我就查询该id的数据,如果用户传来了address,那么我就我们添加address的查询条件,

如果用户传来了username, 那么我就添加username的查询条件,最后如果用户任何一个查询条件都没有添加进来,

那么默认查询条件就是查询id小于10的所有数据。


3 、在上面的案例中小伙伴们可能都发现了一个问题,就是我们在添加查询条件的时候,在查询条件之前都先添加了where 1=1,

 然后后面直接在这之后再追加and什么什么的,那么每次这样来写显然有点麻烦,有没有简单一点的方案呢?

当然有,我们可以通过where元素,只有where元素中有条件成立,才会将where关键字组装到SQL中,这样就比前一种方式简单许多


4、 trim有点元素替换的意思,还是上面的案例,我们可以将and替换为where,

set是我们在更新表的时候使用的元素,通过set元素,我们可以逐字段的修改一条数据 在set元素中,如果遇到了逗号,系统会自动将之去除


5、foreach元素用来遍历集合,比如我想查询多个城市的人,

我的sql语句可能是这样SELECT * FROM user2 WHERE address IN(‘成都’,‘北京’),我在查询的时候可能只是传入了一个list集合,

该集合中有成都和北京两个查询条件,那我如何将这个集合组装成一个sql语句呢?


6、collection表示传入的参数中集合的名称,index表示是当前元素在集合中的下标,

open和close则表示如何将集合中的数据包装起来,separator表示分隔符,item则表示循环时的当前元素。

这样一段配置最终组合成的sql就是SELECT * FROM user2 WHERE address IN(‘成都’,‘北京’)。

(IN关键字既可以指定范围,也可以表示子查询。)


7、bind使用bind元素我们可以预先定义一些变量,然后在查询语句中使用



标签动态查询:查询user表的变量值

<!--数据中表的属性-->
<insert id="addUser" parameterType="com.weixiao.User">
   insert into user(name, type, school) value (#{name}, #{type}, #{school})
</insert>

<delete id="delUserById" parameterType="integer">
   delete from user where id=#{id}
</delete>

<select id="findAllUser" resultMap="userResult">
   select * from user;
</select>


--------------------------------------------------------------

什么叫反射?反射的坏处是什么?有哪些反射的应用场景?


什么叫反射


1、在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;

对于任意一个对象,都能够调用它的任意一个方法和属性

这种动态获取信息以及动态调用对象的方法的功能称为java语言的反射机制


2.反射的优点:

反射提高了程序的灵活性和扩展性,降低耦合性,提高自适应能力。它允许程序创和控制任何类的对象,无需提前硬编码目标类


3.反射的缺点

性能问题,使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。

因此反射机制主要应用在对灵活性和扩展性要求很高的系统框架上,普通程序不建议使用


反射的应用场景

在我们平时的项目开发过程中,基本上很少会直接使用到反射机制,但这不能说明反射机制没有用,

实际上有很多设计、开发都与反射机制有关,例如模块化的开发,通过反射去调用对应的字节码;

动态代理设计模式也采用了反射机制,还有我们日常使用的 Spring/Hibernate 等框架,

也是利用CGLIB 反射机制才得以实现,下面就举例最常见的两个例子,来说明反射机制的强大之处:




之前日报的存在的代码理解问题:

<!--resultMap 元素用来描述如何将结果集映射到 Java 对象-->
   <resultMap id="userResult" type="com.weixiao.User">
       <id property="id" column="id" jdbcType="INTEGER"/>
<!-- property 属性则表示查询出来的字段对应的值赋给实体对象的哪个属性。
    column 属性表示从数据库中查询的字段名或别名-->
       <result property="name" column="name"/>
       <result property="type" column="type"/>
       <result property="school" column="school"/>
   </resultMap>


明天计划:将剩下的深度思考解决







返回列表 返回列表
评论

    分享到